#include "down_and_up.h"
#include "cmd2.h"
#include "cmd1.h"
#define save_path "server_storage/"

void sha256_file(const char *filename, char *output_hash) {
    FILE *fp = fopen(filename, "rb");
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX ctx;
    SHA256_Init(&ctx);

    char buffer[1024];
    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), fp))) {
        SHA256_Update(&ctx, buffer, bytes);
    }
    SHA256_Final(hash, &ctx);
    fclose(fp);

    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        sprintf(output_hash + (i * 2), "%02x", hash[i]);
    }
    output_hash[64] = '\0';
}




int getsfunc(int sockfd,int cur_id,MYSQL *mysql) {
    trains_t packet;

    // 1. 接收客户端发送的哈希
    recv(sockfd, &packet, sizeof(packet), MSG_WAITALL);
    char file_hash[1024]={0}; 
    memcpy(file_hash,packet.hash,strlen(packet.hash));

    // 2. 检查哈希是否已存在
    char ntx[100]={0};
    int file_exists = get_file_hash_from_db1(&cur_id,mysql,file_hash);
    send(sockfd, &file_exists, sizeof(file_exists), 0);
    printf("%d\n",file_exists);
    //3.接收文件名和大小
    recv(sockfd, &packet, sizeof(packet), MSG_WAITALL);
    char filename[1024] = {0};
    memcpy(filename,packet.data,strlen(packet.data));
    off_t file_size;
    memcpy(&file_size, packet.data + strlen(filename) + 1, sizeof(file_size));
    printf("no.1  filename=%s\n",filename);
    char errbuf[1024]={0};
    if (file_exists) {
        printf("filename:%s,cur_id:%d,file_size:%ld",filename,cur_id,file_size);
        insertFile(mysql,filename,cur_id,file_hash,file_size,errbuf);
        printf("[Server] File already exists (hash: %s)\n", file_hash);
        return 0;
    }

    // 4. 断点续传：检查已接收的字节数
    char filepath[256]={0};
    strcpy(filepath,save_path);
    strcat(filepath,filename);
    printf("filename=%s",filename);
    char file_name[1024]={0};
    memcpy(file_name,filename,strlen(filename));

    /* snprintf(filepath, sizeof(filepath), "server_storage/%s", filename); */
    off_t offset = 0;
    printf("filepath=%s\n",filepath);
    struct stat st;
    if (stat(filepath, &st) == 0) {
        offset = st.st_size;  // 文件已部分存在
    }
    send(sockfd, &offset, sizeof(offset), 0);

    // 5. 接收文件数据
    char filepath1[1024]={0};
    strcpy(filepath1,save_path);
    strcat(filepath1,file_hash);
    printf("file_hash:%s\n",file_hash);
    int fd = open(filepath1, O_WRONLY | O_CREAT | (offset ? O_APPEND : O_TRUNC), 0666);
    lseek(fd, offset, SEEK_SET);
    while (1) {
        int ret=recv(sockfd, &packet, sizeof(packet), MSG_WAITALL);
        ERROR_CHECK(ret,-1,"recv");
        if(ret==0&&packet.length!=0){
            break;
        }
        printf("length=%d\n",packet.length);
        if (packet.length == 0) break;  // 结束标志
        write(fd, packet.data, packet.length);
    }
    close(fd);

    // 6. 校验文件哈希
    char server_hash[512];
    /* char sha256_path[1024]={0}; */
    /* strcat(sha256_path,save_path); */
    /* strcat(sha256_path,file_hash); */
    sha256_file(filepath1, server_hash);
    if (strcmp(server_hash, file_hash) != 0) {
        printf("[Server] Hash mismatch! File may be corrupted.\n");
        unlink(filepath);  // 删除无效文件
        return -1;
    }
    printf("filename:%s\n",filename);
    int j=-1;
    for(int i=0;i<strlen(filename);i++)
    {
        if(filename[i]=='/')
            j=i;
    }
    int k=strlen(filename);
    for(int i=0;i<k-j;i++)
    {
        filename[i]=filename[i+j+1];
    }
    filename[k-j]='\0';

    // 7. 写入数据库
    //db_insert_file(filename, filepath, file_size, file_hash);
    char mesage[100];
    printf("down file_name=%s\n",filename);
    insertFile(mysql,file_name,cur_id,file_hash,file_size,mesage);
    printf("[Server] File saved: %s\n", filepath);
    printf("filepath:%s\n",filepath);
    printf("hash=%s\n",file_hash);
    return 0;
}


int putsfunc(int sockfd,int cur_id,MYSQL *mysql) {
    trains_t packet;

    // 1. 接收客户端请求的文件名
    recv(sockfd, &packet, sizeof(packet), MSG_WAITALL);
    char filename[1024] ={0};
    strcpy(filename,packet.data);
    printf("[Server] Client requested file: %s\n", filename);
    char q[1024]={0};
    sprintf(q,"select md5 from vft where parent_id =%d and filename = '%s'; ",cur_id,filename);
    mysql_query(mysql,q);
    MYSQL_RES *rows=mysql_store_result(mysql);
    // 2. 检查文件是否存在
    if(mysql_num_rows(rows)==0){
        return -1;
    }
    MYSQL_ROW row=mysql_fetch_row(rows);
    char *p=(char*)calloc(1024,sizeof(char));
    sprintf(p,"select path from vft where id = %d;",cur_id);
    mysql_query(mysql,p);
    //获得文件的md5
    char file_md5[1024]={0};
    memcpy(file_md5,row[0],strlen(row[0]));
    printf("md5=%s\n",file_md5);
    // 3. 发送文件大小和哈希（从数据库读取）
    struct stat st;
    char filepath[1024]={0};
    strcpy(filepath,save_path);
    strcat(filepath,file_md5);
    printf("filepath=%s\n",filepath);
    int fd=open(filepath,O_RDONLY);
    printf("fd=%d\n",fd);
    fstat(fd,&st);
    off_t file_size = st.st_size;
    send(sockfd,&file_size,sizeof(file_size),0);
    printf("file_size=%ld\n",file_size);
    strncpy(packet.hash, file_md5,sizeof(file_md5));
    packet.length = sizeof(file_size);
    send(sockfd, &packet, sizeof(packet), 0);

    // 4. 接收客户端断点偏移量
    off_t offset;
    recv(sockfd, &offset, sizeof(offset), 0);
    printf("[Server] Client resuming from offset: %ld\n", offset);

    // 5. 分块发送文件数据
    char met[500]={0};
    strcpy(met,save_path);
    strcat(met,filename);
    lseek(fd, offset, SEEK_SET);

    while (offset < file_size) {
        ssize_t bytes_read = read(fd, packet.data, sizeof(packet.data));
        packet.length = bytes_read;
        send(sockfd, &packet, sizeof(packet), 0);
        offset += bytes_read;
    }

    // 6. 发送结束标志
    packet.length = 0;
    send(sockfd, &packet, sizeof(packet), 0);
    close(fd);
    return 0;
}

